home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1998 March / Macworld (1998-03) (Disk 1).dmg / Shareware World / Utilities / Text Processing / Alpha / Tcl / Packages / modeSearchPaths.tcl < prev    next >
Encoding:
Text File  |  1997-12-11  |  10.5 KB  |  405 lines  |  [TEXT/ALFA]

  1. ## -*-Tcl-*- (install)
  2.  # ###################################################################
  3.  #    Vince's    Additions -    an extension package for Alpha
  4.  # 
  5.  #    FILE: "modeSearchPaths.tcl"
  6.  #                                      created: 3/12/96 {6:35:25 pm}    
  7.  #                                  last update: 11/12/97 {9:35:57 am}    
  8.  #    Author:    Vince Darley
  9.  #    E-mail:    <darley@fas.harvard.edu>
  10.  #      mail:    Division of    Applied    Sciences, Harvard University
  11.  #            Oxford Street, Cambridge MA    02138, USA
  12.  #       www:    <http://www.fas.harvard.edu/~darley/>
  13.  #    
  14.  # ###################################################################
  15.  ##
  16.  
  17. alpha::extension modeSearchPaths 1.2 {
  18.     menu::insert mode items 6 \
  19.         "viewSearchPath" "appendSearchPaths…" "removeSearchPaths…" "(-"
  20.     newPref binding openSelection "<O<B/H" searchPaths
  21.     newPref binding sourceHeaderToggle "<O/f" searchPaths
  22.     menu::insert winUtils items end \
  23.         "[menu::bind searchPathsmodeVars(sourceHeaderToggle) -]" \
  24.         "[menu::bind searchPathsmodeVars(openSelection) -]"
  25.     menu::insert global items 5 "searchPathPrefs…"
  26. # make sure we've loaded the old version of this proc
  27. catch {file::tryToOpen blah blah blah blah}
  28.  
  29. # ◊◊◊◊ Try to open the given name or selection ◊◊◊◊ #
  30. proc file::tryToOpen {{fname ""}} {
  31.     if {$fname == ""} {set fname [getSelect]}
  32.     if ![catch {file::_tryToOpen $fname ""}] {
  33.         return
  34.     }
  35.     global headerSuffices sourceSuffices
  36.     if { [file extension ${fname}] == "" } {
  37.         if ![catch {file::_tryToOpen $fname $headerSuffices}] {
  38.             return
  39.         }
  40.         if ![catch {file::_tryToOpen $fname $sourceSuffices}] {
  41.             return
  42.         }
  43.     }
  44.     if {[askyesno "'$fname' can not be found, do you wish to add an include path?"]} {
  45.         mode::appendSearchPath [string trimright [get_directory] ":"]
  46.         mode::modifySearchPath
  47.         return [file::tryToOpen $fname]
  48.     }
  49.     error "Couldn't find anything"
  50. }
  51. } uninstall this-file maintainer {
  52.     "Vince Darley" darley@fas.harvard.edu <http://www.fas.harvard.edu/~darley/>
  53. } help {
  54.     Over-rides the default 'Option title-bar clicking routines',
  55.     allowing them to search more widely, and provides general 
  56.     procedures to find files from mode-specific lists of paths, 
  57.     plus handling of a new 'include paths' section of the 
  58.     'config->current mode' menu.
  59.     
  60.     By default 'opt-cmd-H' is bound to "openSelection"
  61.     and 'cmd-F2' is bound to "sourceHeaderToggle"
  62.     
  63.     You can change these items in the dialog, but you need to
  64.     restart to have the changes take effect.
  65.     
  66.     This code can also handle the creation and manipulation of
  67.     an 'search paths' menu.  You have to attach the menu to
  68.     a given mode's menu.
  69. }
  70.  
  71. proc global::searchPathPrefs {} {
  72.     global mode searchPathsmodeVars
  73.     if {$mode != ""} {
  74.         set searchPathsmodeVars(${mode}ModeSearchPath) [mode::getSearchPath]
  75.         dialog::pkg_options searchPaths
  76.         if {[set searchPathsmodeVars(${mode}ModeSearchPath)] != [mode::getSearchPath]} {
  77.             mode::setSearchPath [set searchPathsmodeVars(${mode}ModeSearchPath)]
  78.         }
  79.         unset searchPathsmodeVars(${mode}ModeSearchPath)
  80.         mode::modifySearchPath
  81.     } else {
  82.         dialog::pkg_options searchPaths
  83.     }
  84. }
  85.  
  86. # ◊◊◊◊ Include paths ◊◊◊◊ #
  87.  
  88. #################################################################
  89. #                                                                #
  90. #    Only _ever_    access include paths through these 4 functions.    #
  91. #                                                                #
  92. #################################################################
  93.  
  94. proc mode::getSearchPath {} {
  95.     global mode 
  96.     global ${mode}SearchPath
  97.     if [info exists ${mode}SearchPath] {
  98.         return [set ${mode}SearchPath]
  99.     } else {
  100.         return ""
  101.     }
  102. }
  103.  
  104. proc mode::setSearchPath {path} {
  105.     global mode 
  106.     global ${mode}SearchPath
  107.     set ${mode}SearchPath $path
  108. }
  109.  
  110. proc mode::removeSearchPath {path} {
  111.     global mode 
  112.     global ${mode}SearchPath
  113.     if [info exists ${mode}SearchPath] {
  114.         set res [lsearch -exact [set ${mode}SearchPath] $path]
  115.         if {$res != -1} {
  116.             set ${mode}SearchPath [lreplace [set ${mode}SearchPath] $res $res]
  117.         }
  118.     }
  119. }
  120.  
  121. proc mode::appendSearchPath {path} {
  122.     global mode 
  123.     global ${mode}SearchPath
  124.     lappend ${mode}SearchPath $path
  125. }
  126.  
  127. # Now we have the functions which manipulate include paths and menus
  128.  
  129. proc mode::modifySearchPath {} {
  130.     global mode modifiedVars 
  131.     if ![catch {mode::getSearchPath} include] {
  132.         lappend modifiedVars ${mode}SearchPath
  133.     }
  134.     mode::rebuildSearchPathMenu
  135. }
  136.  
  137. proc mode::rebuildSearchPathMenu {{name ""}} {
  138.     global mode
  139.     global ${mode}modeVars ${mode}SearchPathMenu
  140.     if {[info exists ${mode}modeVars(includeMenu)] \
  141.       && [set ${mode}modeVars(includeMenu)]} {
  142.         if {$name == ""} {
  143.             if [info exists ${mode}SearchPathMenu] {
  144.                 set name [set ${mode}SearchPathMenu]
  145.             } else {
  146.                 set name headers
  147.             }
  148.         } else {
  149.             set ${mode}SearchPathMenu $name
  150.         }
  151.         set paths {}
  152.         foreach p [mode::getSearchPath] {
  153.             lappend paths "[dialog::specialView_file $p]&"
  154.         }
  155.         menu -n $name -p mode::includeProc -m [concat {
  156.             "Open"
  157.             "Add Folder…"
  158.             "Remove Folder…"
  159.             "(-"
  160.         } $paths]
  161.     }
  162. }
  163.  
  164. proc mode::checkSearchPath {} {
  165.     set    bad    0
  166.     if [catch {mode::getSearchPath}] {return [mode::appendSearchPaths]}
  167.     set    newInc {}
  168.     foreach    p [mode::getSearchPath] {
  169.         if {![file exists $p]} {
  170.             set    bad    1
  171.         } else {
  172.             lappend    newInc $p
  173.         }
  174.     }
  175.     if $bad    {
  176.         mode::setSearchPath $newInc
  177.         mode::modifySearchPath
  178.     }
  179.     return $newInc
  180. }
  181.  
  182. # Now the functions the user sees
  183.  
  184. proc mode::viewSearchPath {} {
  185.     global mode
  186.     listpick -p "Include paths for '$mode' mode:" [mode::getSearchPath]
  187. }
  188.  
  189. proc mode::removeSearchPaths {} {
  190.     global mode
  191.     set remove [listpick -p "Remove which items from '$mode' mode's search path:" -l [mode::getSearchPath]]
  192.     foreach r $remove {
  193.         mode::removeSearchPath $r
  194.     }
  195.     mode::modifySearchPath
  196. }
  197.  
  198. proc mode::appendSearchPaths {} {
  199.     if [catch {mode::getSearchPath}] {
  200.         mode::setSearchPath {}
  201.     }    
  202.     while {![catch {set    path [get_directory]}]}    {
  203.         set    path [string trimright $path : ]
  204.         mode::appendSearchPath $path
  205.     }
  206.     mode::modifySearchPath
  207. }
  208.  
  209. proc mode::includeProc {menu item} {
  210.     switch $item {
  211.         "Open"    {
  212.             set text [getText [lineStart [getPos]] [nextLineStart [getPos]]]
  213.             if {[regexp {["<]([^">]*)[">]} $text dummy fname]} {
  214.                 file::tryToOpen $fname
  215.             }
  216.         }
  217.         "Add Folder" { 
  218.             mode::appendSearchPath [string trimright [get_directory] ":"]
  219.             mode::modifySearchPath
  220.         }
  221.         "Remove Folder" {
  222.             mode::removeSearchPath [listpick -p "Remove which folder?" [lsort [mode::getSearchPath]]]
  223.             mode::modifySearchPath
  224.         }
  225.         default {
  226.             set i [lsearch -glob [mode::getSearchPath] $item]
  227.             if {$i != -1} {
  228.                 if {[askyesno "Shall I reveal this folder in the finder?"] == "yes"} {
  229.                     openFolder [lindex [mode::getSearchPath] $i]
  230.                 }
  231.             } else {
  232.                 alertnote "Sorry, Alpha has a bug which can affect this menu.  I can't find that particular folder."
  233.             }
  234.         }
  235.         
  236.     }
  237. }
  238.  
  239. proc file::_tryToOpen {fname suffices} {
  240.     # first try basic open
  241.     if ![catch {file::_tryToOpenIn $fname [list [file dir [win::Current]]] $suffices}] {
  242.         return
  243.     }
  244.     # now try in mode include path
  245.     if ![catch {file::_tryToOpenIn $fname [mode::getSearchPath] $suffices}] {
  246.         return
  247.     }
  248.     # now try in common paths
  249.     if ![catch {file::_tryToOpenIn $fname [file::_MakeCommonPaths [file dirname [win::Current]]] $suffices}] {
  250.         return
  251.     }
  252.     
  253.     error "Couldn't find anything"
  254. }
  255.  
  256. ## 
  257.  # -------------------------------------------------------------------------
  258.  #     
  259.  #    "fileMakeCommonPaths" --
  260.  #    
  261.  #     Given a directory make    a path of common search    possibilities which
  262.  #     could pertain to that directory.  This    is done    by matching    possible
  263.  #     Source/Header directory pairs,    and    by adding the mode-dependent
  264.  #     'includePath' variable.
  265.  # -------------------------------------------------------------------------
  266.  ##
  267. proc file::_MakeCommonPaths { thisdir } {
  268.     # allow for some common possibilities of separating
  269.     # source and header files
  270.     set path [list $thisdir]
  271.     
  272.     foreach src { Source src source Src } {
  273.         if { [file tail $thisdir] == $src } {
  274.             foreach dir { Headers headers Header header } {
  275.                 lappend path [file dirname $thisdir]:$dir
  276.             }
  277.             break
  278.         }
  279.     }
  280.  
  281.     foreach src { Headers headers Header header } {
  282.         if { [file tail $thisdir] == $src } {
  283.             foreach dir { Source src source Src } {
  284.                 lappend path [file dirname $thisdir]:$dir
  285.             }
  286.             break
  287.         }
  288.     }
  289.  
  290.     return $path
  291. }
  292.  
  293.  
  294. proc file::_tryToOpenIn { filelist path {suffices ""}} {
  295.     set w [win::Current]
  296.     foreach dir $path {
  297.         foreach ff $filelist {
  298.             if {$suffices != ""} {
  299.                 foreach sfx $suffices {
  300.                     if {[file exists $dir:$ff$sfx] && "$dir:$ff$sfx" != $w} {
  301.                         openFileQuietly $dir:$ff$sfx
  302.                         return
  303.                     }
  304.                 }
  305.             } else {
  306.                 if {[file exists $dir:$ff] && "$dir:$ff" != $w} {
  307.                     openFileQuietly $dir:$ff
  308.                     return
  309.                 }                
  310.             }
  311.         }
  312.     }
  313.     error "Couldn't find anything"
  314. }
  315.  
  316.  
  317. ## 
  318.  # ----------------------------------------------------------------------
  319.  #     
  320.  #    "file::sourceHeaderToggle" --
  321.  #    
  322.  #     Toggles the front window back and forth between a header/source
  323.  #     pair. Requires    that "headerSuffices" and "sourceSuffices" be
  324.  #     defined for whatever mode it is used in.
  325.  #    
  326.  #    Side effects:
  327.  #     A different window    is (perhaps    opened)    and    uppermost
  328.  #    
  329.  # ----------------------------------------------------------------------
  330.  ##
  331. proc file::sourceHeaderToggle {} {
  332.     set ff [win::CurrentTail]
  333.     set fbase [file::baseName $ff]
  334.     set m [modeALike]
  335.     if [file::isSource $ff] {
  336.         global headerSuffices
  337.         file::_tryToOpen ${fbase} $headerSuffices
  338.     } elseif [file::isHeader $ff] {
  339.         global sourceSuffices
  340.         file::_tryToOpen ${fbase} $sourceSuffices
  341.     } else {
  342.         # don't recognise this file
  343.         beep
  344.         message "I don't recognise the file extension. Set your 'sourceSuffices' and 'headerSuffices'"
  345.         return
  346.     }
  347. }
  348.  
  349.  
  350. ## 
  351.  # ----------------------------------------------------------------------
  352.  # 
  353.  #    "openSelection"    --
  354.  # 
  355.  #     Opens the header file currently selected, or else if that
  356.  #     fails,    calls file::sourceHeaderToggle.  Each mode can have a variable
  357.  #     'includePath' defined,    in which this procedure    searches.
  358.  # 
  359.  # ----------------------------------------------------------------------
  360.  ##
  361. proc file::openSelection {} {
  362.     file::tryToOpen
  363. }
  364.  
  365. # three simple utility procedures
  366.  
  367. proc file::isHeader { filename {m ""}} {
  368.     if {$m == ""} {
  369.         global headerSuffices
  370.         set var "headerSuffices"
  371.     } else {
  372.         global dummyProc
  373.         if {[info exists dummyProc($m)]} { $dummyProc($m) }
  374.         global ${m}modeVars
  375.         set var "${m}modeVars(headerSuffices)"
  376.     }
  377.     return [file::_listContains $var [file extension $filename]]
  378.  
  379. proc file::isSource { filename {m ""}} {
  380.     if {$m == ""} {
  381.         global sourceSuffices
  382.         set var "sourceSuffices"
  383.     } else {
  384.         global dummyProc
  385.         if {[info exists dummyProc($m)]} { $dummyProc($m) }
  386.         global ${m}modeVars
  387.         set var "${m}modeVars(sourceSuffices)"
  388.     }
  389.     return [file::_listContains $var [file extension $filename]]
  390. }
  391.  
  392. proc file::_listContains {listvar item} {
  393.     upvar $listvar a
  394.     if [info exists a] {
  395.         return [expr [lsearch -exact $a $item] != -1] 
  396.     } else {
  397.         return 0
  398.     }
  399. }
  400.  
  401. proc file::baseName { filename } { return [file root [file tail $filename]] }
  402.  
  403.  
  404.